哈夫曼编码

哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码)。

原理

设某信源产生有五种符号u1、u2、u3、u4和u5,对应概率P1=0.4,P2=0.1,P3=P4=0.2,P5=0.1。首先,将符号按照概率由大到小排队,如图所示。编码时,从最小概率的两个符号开始,可选其中一个支 路为0,另一支路为1。这里,我们选上支路为0,下支路为1。再将已编码的两支路的概率合并,并重新排队。多次重复使用上述方法直至合并概率归一时为止。从图(a)和(b)可以看出,两者虽平均码长相等,但同一符号可以有不同的码长,即编码方法并不唯一,其原因是两支路概率合并后重新排队时,可能出现几个支路概率相等,造成排队方法不唯一。一般,若将新合并后的支路排到等概率的最上支路,将有利于缩短码长方差,且编出的码更接近于等长码。这里图(a)的编码比(b)好。
图1 赫夫曼编码原理 图1 赫夫曼编码原理
赫夫曼码的码字(各符号的代码是异前置码字,即任一码字不会是另一码字的前面部分,这使各码字可以连在一起传送,中间不需另加隔离符号,只要传送时不出错,收端仍可分离各个码字,不致混淆。
实际应用中,除采用定时清洗以消除误差扩散和采用缓冲存储以解决速率匹配以外,主要问题是解决小符号集合的统计匹配,例如黑(1)、白(0)传真信源的统计匹配,采用0和1不同长度游程组成扩大的符号集合信源。游程,指相同码元的长度(如二进码中连续的一串0或一串1的长度或个数)。按照CCITT标准,需要统计2×1728种游程(长度),这样,实现时的存储量太大。事实上长游程的概率很小,故CCITT还规定:若l表示游程长度,则l=64q+r。其中q称主码,r为基码。编码时,不小于64的游程长度由主码和基码组成。而当l为64的整数倍时,只用主码的代码,已不存在基码的代码。
长游程的主码和基码均用赫夫曼规则进行编码,这称为修正赫夫曼码,其结果有表可查。该方法已广泛应用于文件传真机中。





定理

在变 字长编码中,如果码字长度严格按照对应符号出现的概率大小逆序排列,则其平 均码字长度为最小。
现在通过一个实例来说明上述定理的实现过程。设将信源符号按出现的概率大小顺序排列为 :
U: ( a1 a2 a3 a4 a5 a6 a7 ) [1]
0.20 0.19 0.18 0.17 0.15 0.10 0.01
给概率最小的两个符号a6与a7分别指定为“1”与“0”,然后将它们的概率相加再与原来的 a1~a5组合并重新排序成新的原为:
U′: ( a1 a2 a3 a4 a5 a6′ )
0.20 0.19 0.18 0.17 0.15 0.11
对a5与a′6分别指定“1”与“0”后,再作概率相加并重新按概率排序得
U″:(0.26 0.20 0.19 0.18 0.17)…
直到最后得 U″″:(0.61 0.39)
赫夫曼编码的具体方法:先按出现的概率大小排队,把两个最小的概率相加,作为新的概率 和剩余的概率重新排队,再把最小的两个概率相加,再重新排队,直到最后变成1。每次相 加时都将“0”和“1”赋与相加的两个概率,读出时由该符号开始一直走到最后的“1”, 将路线上所遇到的“0”和“1”按最低位到最高位的顺序排好,就是该符号的赫夫曼编码。
例如a7从左至右,由U至U″″,其码字为0000;
a6按路线将所遇到的“0”和“1”按最低位到最高位的顺序排好,其码字为0001…
用赫夫曼编码所得的平均 比特率为:Σ码长×出现概率
上例为:0.2×2+0.19×2+0.18×3+0.17×3+0.15×3+0.1×4+0.01×4=2.72 bit
可以算出本例的信源熵为2.61bit,二者已经是很接近了。

哈夫曼树


如何构造
然而怎样构造一棵 哈夫曼树呢?最具有一般规律的 构造方法就是 哈夫曼算法。一般的数据结构的书中都可以找到其描述:

构成初始集合

对给定的n个 权值{W1,W2,W3,...,Wi,...,Wn}构成n棵 二叉树的初始集合F={T1,T2,T3,...,Ti,...,Tn},其中每棵二叉树Ti中只有一个权值为Wi的 根结点,它的左右子树均为空。(为方便在计算机上实现算法,一般还要求以Ti的权值Wi的升序排列。)

选取左右子树

在F中选取两棵 根结点 权值最小的树作为新构造的 二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和。

删除左右子树

从F中删除这两棵树,并把这棵新的 二叉树同样以升序排列加入到集合F中。

重复二和三两步

重复二和三两步,直到集合F中只有一棵 二叉树为止。
用C语言实现上述算法,可用静态的二叉树或动态的二叉树。若用动态的二叉树可用以下数据结构: struct tree{
float weight; /* 权值*/
union{
char leaf; /*叶结点信息 字符*/
struct tree *left; /*树的左结点*/
};
struct tree *right; /*树的右结点*/
};
struct forest{ /*F集合,以 链表形式表示*/
struct tree *ti; /* F中的树*/
struct forest *next; /* 下一个结点*/
};
例:若字母A,B,C,D出现的概率为:0.75,0.54,0.28,0.43;则相应的 权值为:75,54,28,43。
构造好 哈夫曼树后,就可根据哈夫曼树进行编码。例如:上面的 字符根据其出现的概率作为权值构造一棵哈夫曼树后,经 哈夫曼编码得到的对应的码值。只要使用同一棵哈夫曼树,就可把编码还原成原来那组字符。显然哈夫曼编码是 前缀编码,即任一个字符的编码都不是另一个字符的编码的前缀,否则,编码就不能进行翻译。例如:a,b,c,d的编码为:0,10,110,111,对于编码串:1010就翻译为bb。刚才进行哈夫曼编码的规则是从 根结点叶结点(包含原信息)的路径,向左孩子前进编码为0,向右孩子前进编码为1,当然你也可以反过来规定。

哈夫曼编码实现


参看不同语言的实现: http://rosettacode.org/wiki/Huffman_coding
wiki算法和动态图展示: https://en.wikipedia.org/wiki/Huffman_coding

参考资料:

http://baike.baidu.com/subview/1436260/1436260.htm

http://baike.baidu.com/link?url=Jx9c-rCmycy8AyRCFN3cvnakRZPrwhlzgdXheQF9ySM_KtfCAyHEKvrs4hwsJKJg_LKWsBGlQfeDVeliCEWKCK



  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 哈夫曼编码是一种使用变长编码来减少数据传输量的有效方法。在 Verilog 中,我们可以通过以下步骤实现哈夫曼编码。 首先,我们需要构建哈夫曼编码树。这棵树是由输入数据的频率构建而成的。可以使用哈夫曼树构建算法,该算法会根据输入数据的频率构造出最优的哈夫曼编码树。 然后,我们需要根据构建好的哈夫曼编码树生成对应的哈夫曼编码表。哈夫曼编码表将字符与对应的二进制编码一一对应起来。可以使用深度优先搜索的方法遍历哈夫曼编码树,生成哈夫曼编码表。 接下来,我们可以编写 Verilog 代码来实现哈夫曼编码。首先,我们需要定义输入数据的接口,并接收输入数据。然后,根据输入的字符,查询哈夫曼编码表,将对应的二进制编码输出。 最后,我们需要将输出的二进制编码进行传输。为了正确传输数据,我们需要在输出数据前加入标志位,表示输出数据的开始位置。在接收端,需要识别这个标志位,并将后续的二进制编码解码为对应的字符。 总结来说,哈夫曼编码在 Verilog 中的实现需要构建哈夫曼编码树,生成哈夫曼编码表,并编写相应的编码和解码逻辑。这样可以实现对输入数据的高效压缩和解压缩。 ### 回答2: 哈夫曼编码是一种基于字符频率来构建编码的最优前缀编码方法。在Verilog中实现哈夫曼编码可以分为两步:构建哈夫曼树和生成编码表。 首先,构建哈夫曼树。我们可以使用二叉树的数据结构来表示哈夫曼树。在Verilog中,可以通过定义一个节点结构体来表示二叉树节点,其中包括字符和频率信息,以及左右子节点指针。通过比较字符频率来构建哈夫曼树,可以采用贪心算法,每次选择频率最小的两个节点合并为一个新节点,直到只剩下一个节点为止。 接下来,生成编码表。通过遍历哈夫曼树,可以得到每个字符的编码。在Verilog中,可以使用递归或者迭代的方式进行树的遍历。当遍历到叶子节点时,记录下路径上的0和1,即可得到每个字符的哈夫曼编码。可以使用一个数据结构来保存字符与编码的对应关系,比如使用一个二维数组或者哈希表。 最后,将哈夫曼编码应用于实际数据压缩或传输中。通过将原始数据按照对应的编码进行替换或者添加额外的标识,可以实现压缩和解压缩的功能。 总之,通过Verilog实现哈夫曼编码需要先构建哈夫曼树,然后生成编码表,最后将编码应用于数据压缩或传输中。这是一个相对复杂的任务,需要熟悉Verilog语言和数据结构的相关知识才能完成。 ### 回答3: 哈夫曼编码是一种变长编码的压缩算法,常用于将频率较高的字符用较短的编码表示,从而减小存储或传输的数据量。为了实现哈夫曼编码,可以使用硬件描述语言Verilog来设计相应的电路。 实现哈夫曼编码的Verilog电路需要以下几个主要模块: 1. 频率统计模块:用于统计输入文本中各个字符的频率。输入文本可以通过数据输入端口传入,使用计数器来统计每个字符出现的次数。 2. 构建哈夫曼树模块:根据字符频率构建哈夫曼树。使用二叉堆等数据结构来优化树的构建过程,按照频率大小进行排序。 3. 哈夫曼编码生成模块:根据构建好的哈夫曼树,生成每个字符对应的哈夫曼编码串。可以使用递归或者迭代的方式遍历哈夫曼树,同时记录每个字符的编码。 4. 编码器模块:将输入的文本按照生成的哈夫曼编码进行编码。通过读取输入文本的每个字符,并查找对应的哈夫曼编码,输出对应的编码串。 5. 译码器模块:将编码后的二进制串按照哈夫曼编码进行译码,得到原始文本。根据哈夫曼编码树进行译码,从根节点开始依次查找对应的字符。 以上模块可以通过组合逻辑电路来实现,可以利用状态机等技术进行控制。此外,还需要提供测试模块,用于验证设计的正确性。 总的来说,通过使用Verilog语言来设计实现哈夫曼编码的电路,可以实现对输入文本进行压缩和解压缩的功能。这种硬件实现可以提高编码运行速度,并减小对系统资源的占用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值